package com.apisix.service.service;

import com.apisix.service.entity.Route;
import com.apisix.service.repository.RouteRepository;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class RouteService {

    private final RouteRepository routeRepository;
    private final ApisixService apisixService;
    private final ObjectMapper objectMapper;

    @Autowired
    public RouteService(RouteRepository routeRepository, ApisixService apisixService, ObjectMapper objectMapper) {
        this.routeRepository = routeRepository;
        this.apisixService = apisixService;
        this.objectMapper = objectMapper;
    }

    public List<Route> getAllRoutes() {
        return routeRepository.findAll();
    }

    public Optional<Route> getRouteById(Long id) {
        return routeRepository.findById(id);
    }

    public Optional<Route> getRouteByRouteId(String routeId) {
        return routeRepository.findByRouteId(routeId);
    }

    @Transactional
    public Route createRoute(Route route) throws JsonProcessingException {
        // 如果未提供路由ID，则生成一个UUID
        if (route.getRouteId() == null || route.getRouteId().isEmpty()) {
            route.setRouteId(UUID.randomUUID().toString());
        }
        
        // 保存到数据库
        Route savedRoute = routeRepository.save(route);
        
        // 在APISIX中创建
        Map<String, Object> routeData = convertToApisixFormat(savedRoute);
        apisixService.createRoute(routeData);
        
        return savedRoute;
    }

    @Transactional
    public Optional<Route> updateRoute(Long id, Route routeDetails) throws JsonProcessingException {
        return routeRepository.findById(id)
                .map(existingRoute -> {
                    // 更新路由信息
                    existingRoute.setName(routeDetails.getName());
                    existingRoute.setUri(routeDetails.getUri());
                    existingRoute.setHost(routeDetails.getHost());
                    existingRoute.setPath(routeDetails.getPath());
                    existingRoute.setMethods(routeDetails.getMethods());
                    existingRoute.setUpstreamId(routeDetails.getUpstreamId());
                    existingRoute.setServiceId(routeDetails.getServiceId());
                    existingRoute.setPlugins(routeDetails.getPlugins());
                    existingRoute.setStatus(routeDetails.getStatus());
                    existingRoute.setDescription(routeDetails.getDescription());
                    
                    Route updatedRoute = routeRepository.save(existingRoute);
                    
                    try {
                        // 在APISIX中更新
                        Map<String, Object> routeData = convertToApisixFormat(updatedRoute);
                        apisixService.updateRoute(updatedRoute.getRouteId(), routeData);
                    } catch (JsonProcessingException e) {
                        throw new RuntimeException("Failed to update route in APISIX", e);
                    }
                    
                    return updatedRoute;
                });
    }

    @Transactional
    public boolean deleteRoute(Long id) {
        return routeRepository.findById(id)
                .map(route -> {
                    // 首先从APISIX中删除
                    apisixService.deleteRoute(route.getRouteId());
                    
                    // 然后从数据库中删除
                    routeRepository.delete(route);
                    return true;
                })
                .orElse(false);
    }

    public boolean existsByRouteId(String routeId) {
        return routeRepository.existsByRouteId(routeId);
    }
    
    @Transactional
    public void syncRoutesFromApisix() {
        List<Map<String, Object>> apisixRoutes = apisixService.getRoutes();
        
        for (Map<String, Object> apisixRoute : apisixRoutes) {
            String routeId = (String) apisixRoute.get("id");
            
            if (!routeRepository.existsByRouteId(routeId)) {
                Route route = new Route();
                route.setRouteId(routeId);
                
                // 提取路由信息
                Map<String, Object> value = (Map<String, Object>) apisixRoute.get("value");
                
                if (value.containsKey("name")) {
                    route.setName((String) value.get("name"));
                }
                
                if (value.containsKey("uri")) {
                    route.setUri((String) value.get("uri"));
                }
                
                if (value.containsKey("host")) {
                    route.setHost((String) value.get("host"));
                }
                
                if (value.containsKey("path")) {
                    route.setPath((String) value.get("path"));
                }
                
                if (value.containsKey("methods")) {
                    try {
                        List<String> methods = (List<String>) value.get("methods");
                        route.setMethods(objectMapper.writeValueAsString(methods));
                    } catch (JsonProcessingException e) {
                        // 忽略转换错误
                    }
                }
                
                if (value.containsKey("upstream_id")) {
                    route.setUpstreamId((String) value.get("upstream_id"));
                }
                
                if (value.containsKey("service_id")) {
                    route.setServiceId((String) value.get("service_id"));
                }
                
                if (value.containsKey("plugins")) {
                    try {
                        route.setPlugins(objectMapper.writeValueAsString(value.get("plugins")));
                    } catch (JsonProcessingException e) {
                        // 忽略转换错误
                    }
                }
                
                if (value.containsKey("status")) {
                    route.setStatus((Integer) value.get("status"));
                }
                
                if (value.containsKey("desc")) {
                    route.setDescription((String) value.get("desc"));
                }
                
                routeRepository.save(route);
            }
        }
    }
    
    private Map<String, Object> convertToApisixFormat(Route route) throws JsonProcessingException {
        Map<String, Object> routeData = new HashMap<>();
        
        routeData.put("id", route.getRouteId());
        
        if (route.getName() != null && !route.getName().isEmpty()) {
            routeData.put("name", route.getName());
        }
        
        if (route.getUri() != null && !route.getUri().isEmpty()) {
            routeData.put("uri", route.getUri());
        }
        
        if (route.getHost() != null && !route.getHost().isEmpty()) {
            routeData.put("host", route.getHost());
        }
        
        if (route.getPath() != null && !route.getPath().isEmpty()) {
            routeData.put("path", route.getPath());
        }
        
        if (route.getMethods() != null && !route.getMethods().isEmpty()) {
            List<String> methods = objectMapper.readValue(route.getMethods(), List.class);
            routeData.put("methods", methods);
        }
        
        if (route.getUpstreamId() != null && !route.getUpstreamId().isEmpty()) {
            routeData.put("upstream_id", route.getUpstreamId());
        }
        
        if (route.getServiceId() != null && !route.getServiceId().isEmpty()) {
            routeData.put("service_id", route.getServiceId());
        }
        
        if (route.getPlugins() != null && !route.getPlugins().isEmpty()) {
            Map<String, Object> plugins = objectMapper.readValue(route.getPlugins(), Map.class);
            routeData.put("plugins", plugins);
        }
        
        if (route.getStatus() != null) {
            routeData.put("status", route.getStatus());
        }
        
        if (route.getDescription() != null && !route.getDescription().isEmpty()) {
            routeData.put("desc", route.getDescription());
        }
        
        return routeData;
    }
} 